package com.github.linkoog.model_designer.ide.editer.dbmodel.gutter;

import com.github.linkoog.model_designer.Icons;
import com.github.linkoog.model_designer.ide.editer.dbmodel.gutter.action.EditTableAction;
import com.github.linkoog.model_designer.ide.editer.dbmodel.gutter.action.ShowDDLAction;
import com.github.linkoog.model_designer.ide.type.ModelYamlFileType;
import com.intellij.codeInsight.daemon.LineMarkerInfo;
import com.intellij.codeInsight.daemon.LineMarkerProviderDescriptor;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.editor.markup.MarkupEditorFilter;
import com.intellij.openapi.editor.markup.MarkupEditorFilterFactory;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.yaml.psi.YAMLFile;
import org.jetbrains.yaml.psi.YAMLKeyValue;
import org.jetbrains.yaml.psi.YAMLMapping;

import javax.swing.*;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;


public class DBModelLineMarkerProvider extends LineMarkerProviderDescriptor {


    @Override
    public LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element) {
        final PsiFile containingFile = element.getContainingFile();
        if (containingFile == null || !containingFile.isValid()) return null;

        final VirtualFile virtualFile = containingFile.getVirtualFile();
        if (virtualFile == null) return null;

        final FileType fileType = virtualFile.getFileType();
        if (!(fileType instanceof ModelYamlFileType)) return null;

        final YAMLFile yamlFile = (YAMLFile) PsiManager.getInstance(element.getProject()).findFile(virtualFile);
        if (yamlFile == null)  return null;


        if (element instanceof YAMLMapping){
            YAMLMapping yamlMapping = (YAMLMapping)element;
            YAMLKeyValue yamlKeyValue = getYAMLMappingKey(yamlMapping);
            if (yamlKeyValue == null){
                return null;
            }

            final PsiElement currentKey = yamlKeyValue.getKey();
            if (currentKey == null){
                return null;
            }

            String currentKeyName = yamlKeyValue.getKeyText();
            YAMLMapping p1YAMLMapping = yamlKeyValue.getParentMapping();
            YAMLKeyValue p1YAMLKeyValue = getYAMLMappingKey(p1YAMLMapping);

            //无父级节点
            if (p1YAMLKeyValue == null){
                if ("datasources".equals(currentKeyName) || "commonColumns".equals(currentKeyName)){
                    return null;
                }

                // table节点
                if (yamlKeyValue.getValue() == null || !(yamlKeyValue.getValue() instanceof YAMLMapping)){
                    return null;
                }
                YAMLMapping tableMapping = (YAMLMapping)yamlKeyValue.getValue();


                //未设置列
                YAMLKeyValue columnsKeyValue = tableMapping.getKeyValueByKey("columns");
                if (columnsKeyValue == null || columnsKeyValue.getValue() == null || !(columnsKeyValue.getValue() instanceof YAMLMapping)){
                    return null;
                }
                YAMLMapping columnsMapping = (YAMLMapping)columnsKeyValue.getValue();


                DefaultActionGroup actionGroup = new DefaultActionGroup();
                ShowDDLAction showDDLAction = new ShowDDLAction(yamlFile, currentKeyName,"show ddl",null, Icons.SQL_2);
                actionGroup.add(showDDLAction);

                EditTableAction editTableAction = new EditTableAction(yamlFile, currentKeyName, "edit table", null, Icons.EDIT);
                actionGroup.add(editTableAction);

                return new RunLineMarkerInfo(currentKey.getNavigationElement(), Icons.TABLE, t -> "表模型", actionGroup, () -> "model");
            }

            String p1KeyName = p1YAMLKeyValue.getKeyText();
            YAMLMapping pp2YAMLMapping = p1YAMLKeyValue.getParentMapping();
            YAMLKeyValue pp2YAMLKeyValue = getYAMLMappingKey(pp2YAMLMapping);
            if (pp2YAMLKeyValue == null && "datasources".equals(p1KeyName) ){
                // 数据源节点
                DefaultActionGroup actionGroup = new DefaultActionGroup();


                return new RunLineMarkerInfo(currentKey.getNavigationElement(), Icons.DATABASE, t -> "数据源", actionGroup, () -> "table");
            }
        }

        return null;
    }

    private YAMLKeyValue getYAMLMappingKey(YAMLMapping yamlMapping){
        if (yamlMapping == null){
            return null;
        }

        final PsiElement psiElement = yamlMapping.getContext();
        if (psiElement instanceof YAMLKeyValue){
            return (YAMLKeyValue)psiElement;
        }
        return null;
    }


    @Override
    public void collectSlowLineMarkers(@NotNull List<? extends PsiElement> list, @NotNull Collection<? super LineMarkerInfo<?>> collection) {

    }

    static class RunLineMarkerInfo extends LineMarkerInfo<PsiElement> {
        private final DefaultActionGroup myActionGroup;

        RunLineMarkerInfo(PsiElement element, Icon icon, Function<PsiElement, String> tooltipProvider, DefaultActionGroup actionGroup, Supplier<String> accessibleNameProvider) {
            super(element, element.getTextRange(), icon, tooltipProvider, null, GutterIconRenderer.Alignment.LEFT, accessibleNameProvider);
            myActionGroup = actionGroup;
        }

        @Override
        public GutterIconRenderer createGutterRenderer() {
            return new LineMarkerGutterIconRenderer<PsiElement>(this) {
                @Override
                public AnAction getClickAction() {
                    return null;
                }

                @Override
                public boolean isNavigateAction() {
                    return true;
                }

                @Override
                public ActionGroup getPopupMenuActions() {
                    return myActionGroup;
                }

                @Override
                protected boolean looksTheSameAs(@NotNull LineMarkerGutterIconRenderer<?> renderer) {
                    RunLineMarkerInfo  myInfo = (RunLineMarkerInfo)this.getLineMarkerInfo();

                    LineMarkerInfo lineMarkerInfo = renderer.getLineMarkerInfo();
                    if (lineMarkerInfo instanceof RunLineMarkerInfo){
                        RunLineMarkerInfo  runLineMarkerInfo = (RunLineMarkerInfo) lineMarkerInfo;
                        return super.looksTheSameAs(renderer) && CompareActionGroup(myInfo, runLineMarkerInfo);
                    }

                    return false;
                }

                private boolean CompareActionGroup(RunLineMarkerInfo  myInfo, RunLineMarkerInfo  rendererInfo){
                    return myInfo.getMyActionGroup() != null && rendererInfo.getMyActionGroup() != null &&
                    Comparing.equal(myInfo.getMyActionGroup(), rendererInfo.getMyActionGroup());
                }
            };
        }

        @NotNull
        @Override
        public MarkupEditorFilter getEditorFilter() {
            return MarkupEditorFilterFactory.createIsNotDiffFilter();
        }

        public DefaultActionGroup getMyActionGroup() {
            return myActionGroup;
        }
    }

    @NotNull
    @Override
    public String getName() {
        return "DBModel";
    }

}
